/*
 * SeekableInputStream
 *
 * Author: Lasse Collin <lasse.collin@tukaani.org>
 *
 * This file has been put into the public domain.
 * You can do whatever you want with this file.
 */

package org.tukaani.xz;

import java.io.IOException;
import java.io.InputStream;

/**
 * Input stream with random access support.
 */
public abstract class SeekableInputStream extends InputStream
{
  /**
   * Seeks <code>n</code> bytes forward in this stream.
   * <p>
   * This will not seek past the end of the file. If the current position is
   * already at or past the end of the file, this doesn't seek at all and
   * returns <code>0</code>. Otherwise, if skipping <code>n</code> bytes would
   * cause the position to exceed the stream size, this will do equivalent of
   * <code>seek(length())</code> and the return value will be adjusted
   * accordingly.
   * <p>
   * If <code>n</code> is negative, the position isn't changed and the return
   * value is <code>0</code>. It doesn't seek backward because it would conflict
   * with the specification of {@link java.io.InputStream#skip(long)
   * InputStream.skip}.
   * 
   * @return <code>0</code> if <code>n</code> is negative, less than
   *         <code>n</code> if skipping <code>n</code> bytes would seek past the
   *         end of the file, <code>n</code> otherwise
   * 
   * @throws IOException might be thrown by {@link #seek(long)}
   */
  public long skip(long n) throws IOException
  {
    if (n <= 0)
      return 0;

    long size = length();
    long pos = position();
    if (pos >= size)
      return 0;

    if (size - pos < n)
      n = size - pos;

    seek(pos + n);
    return n;
  }


  /**
   * Gets the size of the stream.
   */
  public abstract long length() throws IOException;


  /**
   * Gets the current position in the stream.
   */
  public abstract long position() throws IOException;


  /**
   * Seeks to the specified absolute position in the stream.
   * <p>
   * Seeking past the end of the file should be supported by the subclasses
   * unless there is a good reason to do otherwise. If one has seeked past the
   * end of the stream, <code>read</code> will return <code>-1</code> to
   * indicate end of stream.
   * 
   * @param pos new read position in the stream
   * 
   * @throws IOException if <code>pos</code> is negative or if a stream-specific
   *           I/O error occurs
   */
  public abstract void seek(long pos) throws IOException;
}
